/*
 * HTTPResponse.c
 *      Author: DePhille
 */


#include "HTTPResponse.h"


/**
 * Creates a new HTTPResponse.
 *
 * @param contents	The contents of the HTTPResponse.
 * @return A new HTTPResponse object.
 */
static PC_HTTPResponse* PC_HTTPResponse_New(const gchar* contents) {
	unsigned long			responseLen;	// Clean-up: No
	gchar*					codeStr;		// Clean-up: Yes
	PC_HTTPResponse*	response;		// Clean-up: No
	const gchar*			splitPos;		// Clean-up: No
	const gchar*			headerStart;	// Clean-up: No
	gchar*					headerPart;		// Clean-up: Yes


	// Check input:
	if (!contents) {
		purple_debug_warning("PidginCote", "PC_HTTPResponse_New: Missing 'contents' parameter.");
		return NULL;
	}

	// Calculate response length:
	responseLen = strlen(contents);
	if (responseLen < 13) {
		// Response too short to contain code:
		purple_debug_error("PidginCote", "PC_HTTPResponse_New: HTTP Response too short to contain status code.\r\n");
		return NULL;
	}

	// Build response object:
	response = g_new(PC_HTTPResponse, 1);
	if (!response) {
		purple_debug_error("PidginCote", "PC_HTTPResponse_New: Unable to allocate PC_HTTPResponse.\r\n");
		return NULL;
	}

	// Find start of Header:
	headerStart = g_strstr_len(contents, -1, "\r\n");
	if (!headerStart) {
		purple_debug_error("PidginCote", "PC_HTTPResponse_New: Response consists of only one line.\r\n");
		return NULL;
	}

	// Split header and contents:
	splitPos = g_strstr_len(contents, -1, "\r\n\r\n");
	if (!splitPos) {
		purple_debug_error("PidginCote", "PC_HTTPResponse_New: Unable to find separation between Headers and contents.\r\n");
		return NULL;
	}
	headerPart = g_strndup(headerStart + 2, (splitPos - (headerStart + 2)));
	response->contents = g_strdup(splitPos + 4);

	// Fetch response code:
	codeStr = g_strndup(contents + 9, 3);
	response->code = g_ascii_strtoull(codeStr, NULL, 10);

	// Fetch headers:
	response->headers = PC_Util_Split(headerPart, "\r\n");

	// Clean-up:
	g_free(codeStr);
	g_free(headerPart);

	// Return:
	return response;
}



/**
 * Gets a header from a HTTPResponse.
 *
 * @param response		The HTTPResponse.
 * @param headerName	Name of the HTTP header to retrieve.
 * @return The value of the header or NULL if not found. Caller gets ownership of string.
 */
static gchar* PC_HTTPResponse_GetHeader(const PC_HTTPResponse* response, const gchar* headerName) {
	const gchar*	curHeader;			// Clean-up: No
	const GList*	curNode;			// Clean-up: No
	gchar*			completeHeaderName;	// Clean-up: Yes
	gsize			headerLen;			// Clean-up: No

	// Check input:
	if (!headerName) {
		return NULL;
	} else if(!response) {
		return NULL;
	}

	// Build complete headername:
	completeHeaderName = g_strdup_printf("%s:", headerName);

	// Traverse headers:
	curNode = response->headers;
	while (curNode) {
		// Make gchar:
		curHeader = (gchar*) curNode->data;
		if (!curHeader) {
			purple_debug_warning("PidginCote", "PC_HTTPResponse_GetHeader: Found invalid node.\r\n");
		} else {
			// Check if this is the header:
			if (PC_Util_Strncmp0(curHeader, completeHeaderName, strlen(completeHeaderName)) == 0) {
				headerLen = strlen(completeHeaderName);
				g_free(completeHeaderName);
				return g_strdup(curHeader + headerLen);
			}
		}

		// Next header:
		curNode = g_list_next(curNode);
	}

	// Nothing found:
	g_free(completeHeaderName);
	purple_debug_warning("PidginCote", "PC_HTTPResponse_GetHeader: Unable to fetch header '%s'.\r\n", headerName);
	return NULL;
}


/**
 * Frees a response object from memory.
 *
 * @param	response	The response.
 */
static void PC_HTTPResponse_Delete(PC_HTTPResponse* response) {
	// Only clean-up if necessary:
	if (response) {
		g_free(response->contents);
		g_list_free(response->headers);
	}

	// Free entire object:
	g_free(response);
}
